﻿
using System.Net.Sockets;
using System.Threading.Tasks;
using ePipe;
using eTask;
using Letter.Net.Sockets;

namespace Letter.Net.Session;

sealed partial class TcpSession<TSnders> : ASession where TSnders : ASocketSnderProvider<TcpSnder>
{
    public TcpSession(Socket socket, in TransportSettings settings, in TcpSocketOperators<TSnders> operators, AConnection connection) 
        : base(socket, settings.memoryPool)
    {
        this.Connection = connection;
        this.RemoteEndPoint = socket.RemoteEndPoint;

        this.SocketRcver = operators.rcver;
        this.SocketSnders = operators.snders;

        var input = Pipeline.CreateStandardPipe(settings.inputOptions);
        var output = Pipeline.CreateStandardPipe(settings.outputOptions);
        this.Application = Pipeline.CreateDuplexPipe(output.Reader, input.Writer);
        this.Transport = Pipeline.CreateDuplexPipe(input.Reader, output.Writer);
        
        this.channelRcver = new TcpSessionRcver(this);
        this.channelSnder = new TcpSessionSnder(this);
    }

    private TcpRcver SocketRcver
    {
        get;
    }

    private TSnders SocketSnders
    {
        get;
    }

    private IDuplexPipe<byte> Application
    {
        get;
    }

    private AConnection Connection
    {
        get;
    }

    public override bool Active
    {
        get { return !this.closed; }
    }
    
    private TcpSessionRcver channelRcver;
    private TcpSessionSnder channelSnder;
    private volatile bool closed = false; 
    
    public override ValueTask StartAsync()
    {
        this.channelRcver.Start();
        this.channelSnder.Start();

        this.Connection.Init(this);
        this.Connection.OnActive();

        return ValueTasks.CompletedTask;
    }
    
    public override async ValueTask CloseAsync()
    {
        if (this.closed)
        {
            return;
        }

        this.closed = true;
        await base.CloseAsync();
        await this.channelRcver.CloseAsync();
        await this.channelSnder.CloseAsync();

        this.SocketRcver.Dispose();
        this.SocketSnders.Dispose();

        this.Connection.OnInactive();
    }
}